const { Op, where } = require("sequelize");
const { Menu, MenuButton } = require("../../../../models");
const utils = require("../../../../utils");
module.exports = {
  // 创建/编辑菜单
  async saveOrUpdate(req, res, next) {
    try {
      const { id } = req.body;
      return id
        ? this.updateMenu(req, res, next)
        : this.saveMenu(req, res, next);
    } catch (error) {
      next(error);
    }
  },

  // 创建菜单
  async saveMenu(req, res, next) {
    try {
      const user = await Menu.create(req.body);
      return user ? res.cc(null, "成功创建菜单") : res.err("创建菜单失败");
    } catch (error) {
      next(error);
    }
  },

  // 更新菜单
  async updateMenu(req, res, next) {
    try {
      // 1、校验菜单是否存在
      let menuItem = await this.checkMenuInfo(req, res, next);
      if (!menuItem) return;
      // 2、组装参数
      await utils.assignEditValue(menuItem, req.body);
      menuItem.parentId = req.body.parentId ?? null; // 不传时默认为null
      // 3、执行更新
      const result = await menuItem.save();
      return result ? res.cc(null, "更新成功") : res.err("更新失败");
    } catch (error) {
      next(error);
    }
  },

  // 获取菜单树
  async getMenuTree(req, res, next) {
    try {
      const menuTree = await Menu.findAll({
        order: [["sort", "ASC"]],
        include: {
          model: MenuButton,
          as: "buttons",
          where: {
            isUse: {
              [Op.in]: req.body.isAll ? [0, 1, null] : [1],
            },
          },
          attributes: ["id", "name", "perms", "sort", "isUse"],
          required: false,
        },
      });
      if (!menuTree) return res.err("获取菜单树失败");

      const dataValuesArr = menuTree.map((item) => item.get({ plain: true }));
      console.log(dataValuesArr);

      // 根据parentId,id组成树结构,下级用children字段接收
      const treeData = await utils.arrToTree(dataValuesArr, {
        id: "id",
        parentId: "parentId",
      });
      // 返回树结构
      return res.cc(treeData, "获取菜单树成功");
    } catch (error) {
      next(error);
    }
  },

  // 删除菜单(必须先删除下级菜单)
  async deleteWithoutSub(req, res, next) {
    try {
      const { id } = req.body;
      if (!id) return res.err("请输入菜单id");

      const menuItem = await Menu.findByPk(id);
      if (!menuItem) {
        return res.err("菜单不存在");
      }

      const treeIdList = await this.getTreeIdList(req, res, next);
      if (treeIdList.length > 1) {
        return res.err("请先删除子菜单");
      }

      const result = await menuItem.destroy();
      return result ? res.cc(null, "删除成功") : res.err("删除失败");
    } catch (error) {
      next(error);
    }
  },

  // 删除菜单(会直接删除所有下级菜单)
  async deleteAllSub(req, res, next) {
    try {
      const { id } = req.body;
      if (!id) return res.err("请输入菜单id");
      const menuItem = await Menu.findByPk(id);
      if (!menuItem) {
        return res.err("菜单不存在");
      }
      const treeIdList = await this.getTreeIdList(req, res, next);
      // 删除所有子菜单
      const result = await Menu.destroy({
        where: {
          id: {
            [Op.in]: treeIdList,
          },
        },
      });
      return result ? res.cc(null, "删除成功") : res.err("删除失败");
    } catch (error) {
      next(error);
    }
  },

  //  校验菜单是否存在、编辑时更改信息
  async checkMenuInfo(req, res, next) {
    try {
      const { id, parentId } = req.body;

      // 判断id的数据是否存在
      const menuItem = await Menu.findByPk(id);
      if (!menuItem) {
        throw new Error("菜单不存在");
      }

      // parentId需存在到数据库中
      if (parentId) {
        const parentMenu = await Menu.findByPk(parentId);
        if (!parentMenu) {
          throw new Error("上级菜单不存在");
        }
      }
      const treeIdList = await this.getTreeIdList(req, res, next);
      if (treeIdList.includes(parentId)) {
        throw new Error("菜单不能作为自己或下级的子菜单");
      }
      return menuItem;
    } catch (error) {
      next(error);
    }
  },

  // 获取菜单列表
  async getTreeIdList(req, res, next) {
    try {
      const { id } = req.body;

      if (!id) return res.err("请输入菜单id");

      const allIdList = await Menu.findAll({
        attributes: ["id", "parentId"],
      });
      if (allIdList.length === 0) return res.cc(null, "菜单不存在");
      // 查询树所有子菜单id
      return await utils.getAllTreeIdByRecursion(allIdList, req.body.id, [id]);
    } catch (error) {
      next(error);
    }
  },

  //检查按钮参数
  async checkButtonInfo(req, checkParentId = false) {
    const { id, parentId } = req.body;
    // 根据checkParentId判断是否需要校验菜单id
    if (checkParentId) {
      if (!parentId) {
        throw new Error("parentId不能为空");
      }
      const menuItem = await Menu.findByPk(parentId);
      if (!menuItem) {
        throw new Error("parentId无效, 需为菜单Id");
      }
    }
    if (!id) {
      throw new Error("id不能为空");
    }
    let buttonItem = await MenuButton.findByPk(id);
    if (!buttonItem) {
      throw new Error("按钮数据不存在");
    }

    return buttonItem;
  },
  // 新增修改按钮权限
  async saveOrUpdatePerms(req, res, next) {
    try {
      const { id } = req.body;
      let result = null;
      if (id) {
        const buttonItem = await this.checkButtonInfo(req, true);
        // 编辑 查询到buttonItem后进行赋值更新
        await utils.assignEditValue(buttonItem, req.body);
        // 执行更新
        result = await buttonItem.save();
      } else {
        // 新增 通过parentId校验后直接创建
        result = await MenuButton.create(req.body);
      }
      const responseStr = id ? "更新" : "新增";
      return result
        ? res.cc(null, `${responseStr}成功`)
        : res.err(`${responseStr}失败`);
    } catch (error) {
      next(error);
    }
  },

  // 删除按钮权限
  async deletePerms(req, res, next) {
    try {
      await this.checkButtonInfo(req);
      // 删除所有子菜单
      const result = await MenuButton.destroy({
        where: {
          id: req.body.id,
        },
      });
      return result ? res.cc(null, "删除成功") : res.err("删除失败");
    } catch (error) {
      next(error);
    }
  },
  // 校验传递的按钮id是否合法
  async checkBtnIds(btnIds) {
    // 不能为空
    if (!btnIds) {
      throw new Error("按钮参数不能为空");
    }
    // 必须是数组
    if (!Array.isArray(btnIds)) {
      throw new Error("按钮参数错误");
    }

    // 不能包含重复的id
    if (new Set(btnIds).size !== btnIds.length) {
      throw new Error("不能包含重复的按钮id");
    }
    // 判断传递的菜单id是否合法
    const btnNum = await MenuButton.count({
      where: {
        id: btnIds,
      },
    });
    if (btnNum !== btnIds.length) {
      throw new Error("部分btnId不存在,请检查后重试");
    }
  },
};
